﻿using System;
using System.ComponentModel;
using System.Windows.Media;

namespace Notoric.ViewModel.Elements.CWNotation
{
    /// <summary>
    /// Represents one line of a staff.
    /// </summary>
    public class StaffLine : VirtualViewModelElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="StaffLine"/> instance.
        /// </summary>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="Staff"/>
        /// </para>
        /// <para>
        /// The staff that directly owns this line.
        /// </para>
        /// </param>
        /// <param name="order">
        /// <para>
        /// Type: <see cref="Int32"/>
        /// </para>
        /// <para>
        /// The order of the staff line (first line has order 0).
        /// </para>
        /// </param>
        internal StaffLine(Staff owner, int order)
            : base(owner)
        {
            this.order = order;
            this.stroke = new SolidColorBrush(owner.Color);

            RegisterToOwnerPropertyChanged<Staff>();
            RegisterToOwnerPropertyChanged<System>();
        }

        #endregion

        #region VirtualViewModelElement Members

        /// <inheritdoc/>
        public override void Dispose()
        {
            UnregisterFromOwnerPropertyChanged<Staff>();
            UnregisterFromOwnerPropertyChanged<System>();
            base.Dispose();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the value of some property of the owner has changed.
        /// </summary>
        /// <remarks>
        /// <para>
        /// <b>Operation:</b><br/>
        /// <b>If the <paramref name="owner"/> was <see cref="Staff"/></b>
        /// <list type="table">
        /// <listheader>
        /// <term>
        ///     Modified Property
        /// </term>
        /// <description>
        ///     Action
        /// </description>
        /// </listheader>
        /// <item>
        /// <term>
        ///     Top, Height, SpaceSize
        /// </term>
        /// <description>
        ///     Raises the <see cref="VirtualViewModelElement.PropertyChanged"/> event for <see cref="Y1"/> and <see cref="Y2"/> properties.
        /// </description>
        /// </item>
        /// <item>
        /// <term>
        ///     Color
        /// </term>
        /// <description>
        ///     Creates a new <see cref="SolidColorBrush"/> with the <see cref="Staff.Color"/> and sets it to the <see cref="Stroke"/> property.
        /// </description>
        /// </item>
        /// </list>
        /// <b>If the <paramref name="owner"/> was <see cref="System"/></b>
        /// <list type="table">
        /// <listheader>
        /// <term>
        ///     Modified Property
        /// </term>
        /// <description>
        ///     Action
        /// </description>
        /// </listheader>
        /// <item>
        /// <term>
        ///     Left
        /// </term>
        /// <description>
        ///     Raises the <see cref="VirtualViewModelElement.PropertyChanged"/> event for the <see cref="X1"/> and <see cref="X2"/> properties.
        /// </description>
        /// </item>
        /// <item>
        /// <term>
        ///     Width
        /// </term>
        /// <description>
        ///     Raises the <see cref="VirtualViewModelElement.PropertyChanged"/> event for the <see cref="X2"/> proeprty.
        /// </description>
        /// </item>
        /// </list>
        /// </para>
        /// </remarks>
        /// <param name="owner">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        protected override void Owner_PropertyChanged(ViewModelElement owner, PropertyChangedEventArgs e)
        {
            if (owner is Staff)
            {
                if (e.PropertyName == "Top" || e.PropertyName == "Height" || e.PropertyName == "SpaceSize")
                {
                    RaisePropertyChanged("Y1");
                    RaisePropertyChanged("Y2");
                }
            }
            else if (owner is System)
            {
                if (e.PropertyName == "Left")
                {
                    RaisePropertyChanged("X1");
                    RaisePropertyChanged("X2");
                }
                else if (e.PropertyName == "Width")
                    RaisePropertyChanged("X2");
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the order of this staff line.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Int32"/>
        /// </para>
        /// <para>
        /// The order of the line in its staff (first line has order 0, second 1, etc.)
        /// </para>
        /// </value>
        public int Order
        {
            get { return order; }
        }

        /// <summary>
        /// Gets the stroke of this staff line.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Brush"/>
        /// </para>
        /// <para>
        /// The brush that will paint the line.
        /// </para>
        /// </value>
        public Brush Stroke
        {
            get { return stroke; }
        }

        /// <summary>
        /// Gets the x-coordinate of the line start point.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The x-coordinate for the start point of the line (in device independent pixels).
        /// </para>
        /// </value>
        public double X1
        {
            get { return FindOwner<System>().Left; }
        }

        /// <summary>
        /// Gets the x-coordinate of the line end point.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The x-coordinate for the end point of the line (in device independent pixels).
        /// </para>
        /// </value>
        public double X2
        {
            get 
            {
                var system = FindOwner<System>();

                return system.Left + system.Width;
            }
        }

        /// <summary>
        /// Gets the y-coordinate of the line start point.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The y-coordinate for the start point of the line (in device independent pixels).
        /// </para>
        /// </value>
        public double Y1
        {
            get 
            {
                var staff = FindOwner<Staff>();

                return staff.Top + staff.Height - order * staff.SpaceSize;
            }
        }

        /// <summary>
        /// Gets the y-coordinate of the line end point.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="Double"/>
        /// </para>
        /// <para>
        /// The y-coordinate for the end point of the line (in device independent pixels).
        /// </para>
        /// </value>
        public double Y2
        {
            get
            {
                var staff = FindOwner<Staff>();

                return staff.Top + staff.Height - order * staff.SpaceSize;
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the value of the <see cref="Order"/> property.
        /// </summary>
        private int order;
        /// <summary>
        /// Holds the value of the <see cref="Stroke"/> property.
        /// </summary>
        private Brush stroke;

        #endregion
    }
}
